use crate::listener::Listeners;
use crate::packet;
use crate::router::Router;
use alloc::boxed::Box;
use futures_util::future::{select, Either};
use unmp_id::Id;
use unmp_link::prelude::*;

/// 配置
pub struct Config {
    /// 本设备ID
    id: Id,
    /// 转发开关
    relay: bool,
    /// 发送数据的默认生命周期
    ttl: u8,
}
impl Config {
    pub fn new(id: Id) -> Self {
        Config {
            id: id,
            relay: false,
            ttl: 8,
        }
    }
    pub fn id(&self) -> &Id {
        &self.id
    }
    pub fn set_id(&mut self, id: Id) {
        self.id = id;
    }
    pub fn relay(&self) -> bool {
        self.relay
    }
    pub fn set_relay(&mut self, relay: bool) {
        self.relay = relay;
    }
}

/// 网络层
pub struct Network {
    pub cfg: Config,
    sn: u8,
    router: Router,
    listeners: Listeners,
}
impl Network {
    pub fn new(cfg: Config) -> Network {
        let mut sn = [0u8];
        getrandom::getrandom(&mut sn).unwrap();
        let router = Router::new(cfg.id.clone(), cfg.relay);
        Self {
            cfg,
            sn: sn[0],
            router,
            listeners: Listeners::new(),
        }
    }
    /// 读取本机ID
    pub fn get_id(&self) -> &Id {
        self.cfg.id()
    }
    /// add Listener
    pub fn add_listener(&mut self, listener: Listener) {
        self.listeners.push(listener);
    }
    /// add Connection
    pub fn add_connection(&mut self, conn: Connection) {
        self.router.add_conn(conn);
    }
    pub fn new_packet(&mut self, target: Id, protocol: u8, data: Bytes) -> packet::Packet {
        self.sn = self.sn.wrapping_add(1);
        let head = packet::Header {
            sn: self.sn,
            src: self.cfg.id.clone(),
            dst: target,
            important: false,
            ttl: self.cfg.ttl,
            protocol,
        };
        packet::Packet { head, data }
    }
}
impl Network {
    /// 接收数据包
    pub async fn recv(&mut self) -> packet::Packet {
        loop {
            let accept = Box::pin(self.listeners.accept());
            let recv = Box::pin(self.router.recv());
            let result = match select(accept, recv).await {
                Either::Left((conn, _)) => Either::Left(conn),
                Either::Right((data, _)) => Either::Right(data),
            };
            match result {
                Either::Left(conn) => {
                    self.router.add_conn(conn);
                }
                Either::Right(packet) => {
                    return packet;
                }
            };
        }
    }
    /// 发送数据包
    pub async fn send(&mut self, packet: packet::Packet) -> Result<(), ()> {
        self.router.send(packet).await
    }
}
